/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.diagram.deployment.helper;

import java.util.ArrayList;
import java.util.Iterator;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.uml2.uml.Artifact;
import org.eclipse.uml2.uml.Deployment;
import org.eclipse.uml2.uml.DeploymentSpecification;
import org.eclipse.uml2.uml.DeploymentTarget;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageableElement;
import org.eclipse.uml2.uml.UMLFactory;

import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.helper.IGraphEdgeHelper;
import com.cea.papyrus.core.helper.IModelerHelper;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagram.deployment.Activator;
import com.cea.papyrus.diagram.deployment.preference.DeploymentDiagramPreferenceConstants;
import com.cea.papyrus.diagraminterchange2.di2.Di2Factory;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;


/**
 * Defines management of deployment specifications.
 * 
 * @author Gilles Cannenterre
 * @since 15 janv. 07
 */
public class NodeDeploymentSpecificationHelper extends NodeArtifactHelper{

	/**
	 * The channel.
	 */
	private int channel = 203;
	
	/**
	 * The imodeler factory.
	 */
	private IModelerHelper imodelerFactory;
	
	/**
	 * The element factory.
	 */
	private Object elementFactory;
	
	/**
	 * The the deployment.
	 */
	private Deployment theDeployment;
	
	/**
	 * The deployment created.
	 */
	private boolean deploymentCreated;

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.helper.NodeHelper#createUMLElement(java.lang.String, org.eclipse.uml2.uml.Element)
	 */
	/**
	 * 
	 * 
	 * @param umlParent 
	 * @param name 
	 * 
	 * @return 
	 */
	@Override
	public  Element createUMLElement(String name, Element umlParent){
		Debug.debug(this,"createUMLElement(String,Element)", channel); 
		DeploymentSpecification aDeploymentSpecification = null;
		if (umlParent instanceof Deployment) {
			aDeploymentSpecification = UMLFactory.eINSTANCE.createDeploymentSpecification();
			aDeploymentSpecification.setName(name);

			// Get the right helper
			imodelerFactory= PapyrusPlugin.getDefault().getFactoryRegistry().getFactory(Deployment.class);
			elementFactory = imodelerFactory.getElementFactory(Deployment.class);			
			
			// Connect the deployment
			((IGraphEdgeHelper)elementFactory).connect(((Deployment)umlParent).getLocation(), aDeploymentSpecification, (Deployment)umlParent);	
			
			// Add deployment specification to the deployment
			((Deployment)umlParent).getConfigurations().add(aDeploymentSpecification);
		} else if (umlParent instanceof DeploymentTarget) {
			aDeploymentSpecification = UMLFactory.eINSTANCE.createDeploymentSpecification();
			aDeploymentSpecification.setName(name);
			
			// Get the right helper
			imodelerFactory= PapyrusPlugin.getDefault().getFactoryRegistry().getFactory(Deployment.class);
			elementFactory = imodelerFactory.getElementFactory(Deployment.class);			
			
			// No deployment...so let's create one
			if ( ((DeploymentTarget)umlParent).getDeployments().isEmpty() ) {			
				// Create the deployment
				Element element = ((IGraphEdgeHelper)elementFactory).createUMLElement( umlParent);			
				theDeployment = ((Deployment)element);
				deploymentCreated = true;
			} else {
				// Get the last deployment
				theDeployment = (Deployment)((DeploymentTarget)umlParent).getDeployments().get(((DeploymentTarget)umlParent).getDeployments().size() - 1);				
				deploymentCreated = false;
			}
			
			// Connect the deployment
			((IGraphEdgeHelper)elementFactory).connect(umlParent, aDeploymentSpecification, theDeployment);	
			
			// Add deployment specification to the deployment
			theDeployment.getConfigurations().add(aDeploymentSpecification);
		} else if (umlParent instanceof Artifact) {
			aDeploymentSpecification = UMLFactory.eINSTANCE.createDeploymentSpecification();
			aDeploymentSpecification.setName(name);
			((Artifact) umlParent).getNestedArtifacts().add(aDeploymentSpecification);			
		} else if (umlParent instanceof Package) {
			aDeploymentSpecification = UMLFactory.eINSTANCE.createDeploymentSpecification();
			aDeploymentSpecification.setName(name);
			((Package) umlParent).getPackagedElements().add(aDeploymentSpecification);	
		} else {
			aDeploymentSpecification = UMLFactory.eINSTANCE.createDeploymentSpecification();
			aDeploymentSpecification.setName(name);
			((Package)umlParent.getNearestPackage()).getPackagedElements().add(aDeploymentSpecification);
		}
		return aDeploymentSpecification;		
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.helper.NodeHelper#getBaseString()
	 */
	/**
	 * 
	 * 
	 * @return 
	 */
	@Override
	public String getBaseString() {
		return "DeploymentSpecification_"; //$NON-NLS-1$
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.factories.NodeFactory#setGraphElementPreferences(com.cea.papyrus.diagraminterchange2.di2.GraphElement)
	 */
	/**
	 * 
	 * 
	 * @param graphElement 
	 */
	@Override
	public void setGraphElementPreferences(GraphElement graphElement) {	
		// Get the preference store
		IPreferenceStore store = Activator.getDefault().getPreferenceStore();
		
		// Set colors and font
		graphElement.setBackgroundColor(DeploymentDiagramPreferenceConstants.getPreferenceDeploymentSpecificationBackgroundColor(store));
		graphElement.setBorderColor(DeploymentDiagramPreferenceConstants.getPreferenceDeploymentSpecificationBorderColor(store));
		graphElement.setFontColor(DeploymentDiagramPreferenceConstants.getPreferenceDeploymentSpecificationFontColor(store));
		FontData[] fontdata = DeploymentDiagramPreferenceConstants.getPreferenceDeploymentSpecificationFont(store);
		if (fontdata.length>0){
			graphElement.setFontFamily(fontdata[0].getName());
			graphElement.setFontSize(fontdata[0].getHeight());
		}
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.helper.NodeHelper#addUMLElement(org.eclipse.uml2.uml.Element, org.eclipse.uml2.uml.Element)
	 */
	/**
	 * 
	 * 
	 * @param element 
	 * @param umlParent 
	 * 
	 * @return 
	 */
	@Override
	public boolean addUMLElement(Element element, Element umlParent) {
		if (umlParent instanceof Deployment) {		
			// Get the right helper
			imodelerFactory= PapyrusPlugin.getDefault().getFactoryRegistry().getFactory(Deployment.class);
			elementFactory = imodelerFactory.getElementFactory(Deployment.class);
			
			// Connect the deployment
			((IGraphEdgeHelper)elementFactory).connect(((Deployment)umlParent).getLocation(), element, (Deployment)umlParent);	
			
			// Add deployment specification to the deployment
			((Deployment)umlParent).getConfigurations().add((DeploymentSpecification)element);
		}
		if (umlParent instanceof DeploymentTarget) {
			// Get the right helper
			imodelerFactory= PapyrusPlugin.getDefault().getFactoryRegistry().getFactory(Deployment.class);
			elementFactory = imodelerFactory.getElementFactory(Deployment.class);			
		
			// No deployment...so let's create one
			if ( ((DeploymentTarget)umlParent).getDeployments().isEmpty() ) {			
				// Create the deployment
				Element elementCreated = ((IGraphEdgeHelper)elementFactory).createUMLElement( umlParent);			
				theDeployment = ((Deployment)elementCreated);	
				deploymentCreated = true;
			} else {
				// Get the last deployment
				theDeployment = (Deployment)((DeploymentTarget)umlParent).getDeployments().get(((DeploymentTarget)umlParent).getDeployments().size() - 1);				
				deploymentCreated = false;
			}
			
			// Connect the deployment
			((IGraphEdgeHelper)elementFactory).connect(umlParent, element, theDeployment);				
					
			// Add deployment specification to the deployment
			return theDeployment.getConfigurations().add((DeploymentSpecification)element);
		}
		if (umlParent instanceof Artifact){
			return ((Artifact)umlParent).getNestedArtifacts().add((Artifact)element);		
		}
		if (umlParent instanceof Package) {
			return ((Package)umlParent).getPackagedElements().add((PackageableElement)element);
		}
		return false;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.factories.NodeFactory#removeElement(org.eclipse.uml2.uml.Element, org.eclipse.uml2.uml.Element)
	 */
	/**
	 * 
	 * 
	 * @param element 
	 * @param umlParent 
	 * 
	 * @return 
	 */
	@Override
	public boolean removeUMLElement(Element element, Element umlParent) {
		if (umlParent instanceof DeploymentTarget){			
			// Get the right helper
			imodelerFactory= PapyrusPlugin.getDefault().getFactoryRegistry().getFactory(Deployment.class);
			elementFactory = imodelerFactory.getElementFactory(Deployment.class);	
			
			// Deconnect the deployment
			((IGraphEdgeHelper)elementFactory).deconnect(umlParent, element, theDeployment);					
			
			// Remove the deployment if created
			if (deploymentCreated){			
				((DeploymentTarget)umlParent).getClientDependencies().remove(theDeployment);
			}
			// Remove deployment target from the nearest package
			((DeploymentTarget)umlParent).getNearestPackage().getPackagedElements().remove(element);			
		}
		if(umlParent instanceof Deployment) {
			return ((Deployment)umlParent).getConfigurations().remove(element);
		}
		if (umlParent instanceof Artifact) {
			return ((Artifact)umlParent).getNestedArtifacts().remove(element);		
		}
		if(umlParent instanceof Package) {
			return ((Package)umlParent).getPackagedElements().remove(element);
		}
		return false;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.helper.NodeHelper#getNewUMLElementName(org.eclipse.uml2.uml.Element)
	 */
	/**
	 * 
	 * 
	 * @param umlParent 
	 * 
	 * @return 
	 */
	@Override
	public String getNewUMLElementName(Element umlParent) {
		String name = ""; //$NON-NLS-1$
	
		// i <10000: avoid infinite loops
		for(int i=0; i< 10001; i++ ) {
			name = getBaseString()+i;
			if (umlParent instanceof Package){
				if(null == ((Package)umlParent).getPackagedElement(name)) {
					return name;
				}
			} else if (umlParent instanceof DeploymentTarget){
				if ( ((DeploymentTarget)umlParent).getDeployments().isEmpty() ) {
					return name;
				} else {
					// Get the last deployment
					Deployment	theDeployment = (Deployment)((DeploymentTarget)umlParent).getDeployments().get(((DeploymentTarget)umlParent).getDeployments().size() - 1);				
					if (null == theDeployment.getConfiguration(name)) {
						return name;
					}
				}	
			} else if (umlParent instanceof Artifact){
				if(null == ((Artifact)umlParent).getNestedArtifact(name)) {
					return name;
				}
			} else if (umlParent instanceof Deployment){
				if(null == ((Deployment)umlParent).getConfiguration(name)) {
					return name;
				}
			} else {
				if(null == ((Package)umlParent.getNearestPackage()).getPackagedElement(name)) {
					return name;
				}
			}
		}
		return getBaseString()+"X"; //$NON-NLS-1$
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.helper.NodeHelper#createGraphElement(org.eclipse.uml2.uml.Element, com.cea.papyrus.diagraminterchange2.di2.GraphElement, org.eclipse.draw2d.geometry.Point, org.eclipse.draw2d.geometry.Dimension)
	 */
	/**
	 * 
	 * 
	 * @param umlChild 
	 * @param size 
	 * @param location 
	 * @param parent 
	 * 
	 * @return 
	 */
	@Override
	public GraphNode createGraphElement(Element umlChild, GraphElement parent, Point location, Dimension size){
		GraphNode graphNode = super.createGraphElement(umlChild, parent, location, size);
		
		// Create property compartment
		GraphNode propertyCompartment=Di2Factory.eINSTANCE.createGraphNode();
		propertyCompartment.setIsVisible(false);
		graphNode.getContained().add(propertyCompartment);
		
		return graphNode;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.factories.NodeFactory#createGraphNode(org.eclipse.uml2.uml.Element, com.cea.papyrus.diagraminterchange2.di2.Diagram)
	 */
	/**
	 * 
	 * 
	 * @param umlElement 
	 * @param diagram 
	 * 
	 * @return 
	 */
	@Override
	public ArrayList createGraphNode(org.eclipse.uml2.uml.Element umlElement, Diagram diagram) {		
		Debug.debug(this,"createGraphNode(Element,Diagram)", channel);
		ArrayList createdNode =super.createGraphNode(umlElement, diagram);
		
		Iterator it =createdNode.iterator();		
		while(it.hasNext()){
			// Get Current node
			GraphNode currentNode=(GraphNode)it.next();
			currentNode.setSize(new Dimension(150,100));
			
			//	Add property list
			GraphNode extentionPointCompartment=Di2Factory.eINSTANCE.createGraphNode();
			extentionPointCompartment.setIsVisible(false);
			currentNode.getContained().add(extentionPointCompartment);
		}		
		return createdNode;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.factories.NodeFactory#canExecuteCreateElement(org.eclipse.uml2.uml.Element)
	 */
	/**
	 * 
	 * 
	 * @param umlParent 
	 * 
	 * @return 
	 */
	@Override
	public boolean canCreateUMLElement(Element umlParent) {
		if ( (umlParent instanceof Package) || 
				(umlParent instanceof DeploymentTarget) || 
				(umlParent instanceof Artifact) || 
				(umlParent instanceof Deployment)) {
			return true;
		}
		return false;
	}

	/**
	 * Gets the graph node size.
	 * 
	 * @return the graph node size
	 */
	public Dimension getGraphNodeSize() {
		return new Dimension(200,100);
	}
}